﻿using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Threading;
using ParallelRuntimeLibrary.Internal;

namespace ParallelRuntimeLibrary
{
    internal sealed class ForLoopTask<T> : Task
    {
        private Func<T> mProducer;

        internal CountdownEvent mLoopEvent;
        private int mF, mT, mS;

        private object mForBody;
        private ParallelLoopState mPLS;

        /*/////////////////////////////////////////////////////////////////////////////////////////////////////*/
        
        public ForLoopTask(string paralleLoopId, object forBody, int from, int to, int step, Func<T> producer, CountdownEvent loopEvent, ParallelLoopState pls)
        {
            mIdentity = paralleLoopId;
            SyncObject = new object();
            mForBody = forBody;
            mF = from; mT = to; mS = step;
            mProducer = producer; mLoopEvent = loopEvent; mPLS = pls;
            mOption = TaskCreationOptions.None;
            mType = TaskType.ForFunction;
        }

        /*////////////////////////////////////////////////////////////////////////////////////////////////////*/

        internal override bool Execute()
        {
            if (mStatus == TaskStatus.Started || mStatus == TaskStatus.Canceled) return false;
            mStatus = TaskStatus.Started;

            Action<int> realBody1 = mForBody as Action<int>;
            if (realBody1 != null)
            {
                for (int i = mF; i < mT; i += mS)
                    realBody1(i);

                return true;
            }

            Action<int, T> realBody2 = mForBody as Action<int, T>;
            if (realBody2 != null)
            {
                var tmp = mProducer(); 

                for (int i = mF; i < mT; i += mS)
                    realBody2(i, tmp);

                return true;
            }

            Action<int, ParallelLoopState> realBody3 = mForBody as Action<int, ParallelLoopState>;
            if (realBody3 != null)
            {
                for (int i = mF; i < mT; i += mS)
                    realBody3(i, mPLS);

                return true;
            }

            Action<int, T, ParallelLoopState> realBody4 = mForBody as Action<int, T, ParallelLoopState>;
            if (realBody4 != null)
            {
                var tmp = mProducer();

                for (int i = mF; i < mT; i += mS)
                    realBody4(i, tmp, mPLS);

                return true;
            }

            return false;
        }

        internal override void MarkAsFinished()
        {
            mLoopEvent.Signal();
        }

    }
}
